package com.superhero.website.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.superhero.common.pojo.PageInput;
import com.superhero.common.pojo.entity.AccessRegistration;
import com.superhero.common.pojo.entity.UserHealthInfo;
import com.superhero.common.pojo.vo.InspectorEnd.HealthInfoListVo;
import com.superhero.common.pojo.vo.PageVo;
import com.superhero.common.pojo.vo.website.AccessStatisticVo;
import com.superhero.common.pojo.vo.website.NumberVo;
import com.superhero.common.pojo.vo.website.StaticObejct;
import com.superhero.common.pojo.vo.website.TemperatureStatisticVo;
import com.superhero.common.repository.AccessRegistrationRepository;
import com.superhero.common.repository.UserHealthInfoRepository;
import com.superhero.common.utils.ExcelUtils;
import com.superhero.common.utils.StaticsUtil;
import com.superhero.website.service.StatisticService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletResponse;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class StatisticServiceImpl implements StatisticService {

    @Autowired
    UserHealthInfoRepository userHealthInfoRepository;
    @Autowired
    AccessRegistrationRepository accessRegistrationRepository;

    @Override
    public AccessStatisticVo getAccessStatistic() {
        AccessStatisticVo access = new AccessStatisticVo();
        // access---set
        List<UserHealthInfo> all = userHealthInfoRepository.findAll();
        List<Integer> totals = StaticsUtil.get3Totals(all);
        access.setTotalHousehold(totals.get(0));
        access.setTotalConfirmed(totals.get(1));
        access.setTotalSuspected(totals.get(2));

        StaticObejct household = new StaticObejct();
        StaticObejct visiter = new StaticObejct();
        // StaticObejct --- set --- x_time
        List x_time = StaticsUtil.getPre7Days();
        household.setX_time(x_time);
        visiter.setX_time(x_time);
        // 均7个数据
        int[] householdInList = new int[7];
        int[] householdOutList = new int[7];
        int[] visiterInList = new int[7];
        int[] visiterOutList = new int[7];

        List<AccessRegistration> inOneWeekList = accessRegistrationRepository.findAllInOneWeek();
        for (AccessRegistration daily : inOneWeekList) {
            DateFormat format = new SimpleDateFormat("yyyy/MM/dd");
            String createTime = format.format(daily.getCreateTime());
            int i = x_time.indexOf(createTime); // 找出该登记表是第几天
            if (i == -1) continue;
            if (daily.getHousehold() == 0) {    // 访客
                if (daily.getInOrOut() == 0) {  // 0是进入小区
                    visiterInList[i]++;
                } else {
                    visiterOutList[i]++;
                }
            } else {                            // 住户
                if (daily.getInOrOut() == 0) {  // 0是进入小区
                    householdInList[i]++;
                } else {
                    householdOutList[i]++;
                }
            }
        }
        // StaticObejct --- set--- chartData ----- visiter
        ArrayList<NumberVo> visitChartData = new ArrayList<>();
        for (int i = 0; i < 7; i++) {   // 7 days
            NumberVo numberVo = new NumberVo();
            // visiter
            numberVo.setPeople_type(0);
            ArrayList<Integer> y_value = new ArrayList<>();
            y_value.add(visiterInList[i]);  // in
            y_value.add(visiterOutList[i]); // out
            numberVo.setY_value(y_value);

            visitChartData.add(numberVo);
        }
        // chartData ----- household
        ArrayList<NumberVo> householdChartData = new ArrayList<>();
        for (int i = 0; i < 7; i++) {   // 7 days
            NumberVo numberVo = new NumberVo();
            // household
            numberVo.setPeople_type(1);
            ArrayList<Integer> y_value = new ArrayList<>();
            y_value.add(householdInList[i]);  // in
            y_value.add(householdOutList[i]); // out
            numberVo.setY_value(y_value);

            householdChartData.add(numberVo);
        }
        // StaticObejct --- set ---- chartData
        household.setChartData(householdChartData);
        visiter.setChartData(visitChartData);
        // access---set
        access.setHousehold(household);
        access.setVisiter(visiter);

        return access;
    }

    @Override
    public TemperatureStatisticVo getTemperatureStatistic() {
        int normal = 0;
        int over = 0;
        int under = 0;
        Double bodyTemperature;
        List<AccessRegistration> all = accessRegistrationRepository.findAll();
        for (AccessRegistration one : all) {
            bodyTemperature = one.getBodyTemperature();
            if (bodyTemperature > 37.5) {
                over++;
            } else if (bodyTemperature >= 36.6) {
                normal++;
            } else {
                under++;
            }
        }
        TemperatureStatisticVo temperatureStatisticVo = new TemperatureStatisticVo();
        temperatureStatisticVo.setOver(over);
        temperatureStatisticVo.setNormal(normal);
        temperatureStatisticVo.setUnder(under);
        temperatureStatisticVo.setOverPercentage((1.0 * over) / (over + normal + under));
        temperatureStatisticVo.setNormalPercentage((1.0 * normal) / (over + normal + under));
        temperatureStatisticVo.setUnderPercentage((1.0 * under) / (over + normal + under));

        return temperatureStatisticVo;
    }

    @Override
    public PageVo accessList(PageInput pageInput, String keyword) {
        Pageable pageable = PageRequest.of(pageInput.getPageNumber(), pageInput.getPageSize());

        // 获取当前用户的所有出入记录
        // 1. 筛选出相应的数据
        Page<AccessRegistration> accessRegistrations = accessRegistrationRepository.findAll(((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = exportAccessListPredicate(root, criteriaBuilder, keyword);
            Predicate[] p = new Predicate[predicates.size()];
            criteriaQuery.orderBy(criteriaBuilder.desc(root.get("createTime")));
            return criteriaBuilder.and(predicates.toArray(p));
        }), pageable);

        // 2.转换为封装的vo
        PageVo result = PageVo.convert(accessRegistrations);
        result.setContent(accessRegistrations.getContent().stream()
                .map(this::acccessRegistrationConvertToHealthInfoListVo).collect(Collectors.toList()));
        return result;
    }

    @Override
    public ExcelWriter exportAccessList(String keyword, HttpServletResponse response) {
        // 获取当前用户的所有出入记录
        // 1. 筛选出相应的数据
        List<AccessRegistration> accessRegistrations = accessRegistrationRepository.findAll(((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = exportAccessListPredicate(root, criteriaBuilder, keyword);
            Predicate[] p = new Predicate[predicates.size()];
            criteriaQuery.orderBy(criteriaBuilder.desc(root.get("createTime")));
            return criteriaBuilder.and(predicates.toArray(p));
        }));

        // 2.转换为封装的vo
        List<HealthInfoListVo> healthInfoListVos = accessRegistrations.stream().map(this::acccessRegistrationConvertToHealthInfoListVo).collect(Collectors.toList());

        if (!CollectionUtil.isEmpty(healthInfoListVos)) {
            // 3. 设置模板头顺序
            ExcelWriter writer = getExportAccessListExcelWriter();
            // 4. 进行写入
            return ExcelUtils.doExcelWriter(null, writer, healthInfoListVos, HealthInfoListVo.class);
        }
        return null;
    }

    private List<Predicate> exportAccessListPredicate(Root<AccessRegistration> root, CriteriaBuilder criteriaBuilder, String keyword) {
        List<Predicate> predicates = new ArrayList<>();
        predicates.add(criteriaBuilder.equal(root.join("user").get("locked"), "0"));
        if (!StringUtils.isEmpty(keyword)) {
            String key = "%" + keyword.trim() + "%";
            String upperKey = "%" + keyword.toUpperCase().trim() + "%";
            // key可为人员姓名、检查人员姓名、出入类型（出/入），检查人员手机号，社区名称的全模糊查询
            Predicate p1 = null, p2 = null, p3 = null, p4 = null, p5 = null;
            p1 = criteriaBuilder.like(criteriaBuilder.upper(root.join("user").get("realName")), upperKey);
            p2 = criteriaBuilder.like(criteriaBuilder.upper(root.join("inspector").get("realName")), upperKey);
            p4 = criteriaBuilder.like(root.join("inspector").get("phone"), key);
            p5 = criteriaBuilder.like(root.join("user").get("userHealthInfo").get("communityLocation"), upperKey);
            if ("出".equals(keyword.trim())) {
                p3 = criteriaBuilder.equal(root.get("inOrOut").as(Integer.class), 0);
                predicates.add(criteriaBuilder.or(p1, p2, p3, p4, p5));
            } else if ("入".equals(keyword.trim())) {
                p3 = criteriaBuilder.equal(root.get("inOrOut").as(Integer.class), 1);
                predicates.add(criteriaBuilder.or(p1, p2, p3, p4, p5));
            } else {
                predicates.add(criteriaBuilder.or(p1, p2, p4, p5));
            }
        }
        return predicates;
    }

    private HealthInfoListVo acccessRegistrationConvertToHealthInfoListVo(AccessRegistration accessRegistration) {
        HealthInfoListVo healthInfoListVo = new HealthInfoListVo();
        BeanUtils.copyProperties(accessRegistration, healthInfoListVo);
        healthInfoListVo.setName(accessRegistration.getUser().getRealName());
        healthInfoListVo.setInspectorName(accessRegistration.getInspector().getRealName());
        healthInfoListVo.setInspectorPhone(accessRegistration.getInspector().getPhone());
        if (accessRegistration.getUser().getUserHealthInfo() != null) {
            UserHealthInfo userHealthInfo = accessRegistration.getUser().getUserHealthInfo();
            healthInfoListVo.setCommunityLocation(userHealthInfo.getCommunityLocation());
            healthInfoListVo.setPersonType(userHealthInfo.getPersonType());
        }
        return healthInfoListVo;
    }

    private ExcelWriter getExportAccessListExcelWriter() {
        ExcelWriter writer = new ExcelWriter(true);
        writer.addHeaderAlias("personType", "人员性质");
        writer.addHeaderAlias("name", "人员姓名");
        writer.addHeaderAlias("inOrOut", "出入类型");
        writer.addHeaderAlias("createTime", "出入时间");
        writer.addHeaderAlias("bodyTemperature", "体温");
        writer.addHeaderAlias("symptomDetail", "详细异常症状");
        writer.addHeaderAlias("inspectorName", "检查人员姓名");
        writer.addHeaderAlias("inspectorPhone", "检查人员联系方式");
        writer.addHeaderAlias("communityLocation", "社区名称");
        return writer;
    }

}
